﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;

namespace PS_WSSDeploy_Package.Settings
{
    public class ConfigContainer
    {
        private const string ConfigFileName = "wssdeploy.config.xml";
        public static Byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
        public static Byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };

        [XmlElement(typeof(Config), ElementName = "Farm")]
        public List<Config> FarmItems { get; set; }

        [XmlElement(typeof(Config), ElementName = "Sandbox")]
        public List<Config> SandboxItems { get; set; }

        public string ActiveFarm { get; set; }
        public string ActiveSandbox { get; set; }

        private Config ActiveFarmConfig { get; set; }
        private Config ActiveSandboxConfig { get; set; }

        public ConfigContainer()
        {
            FarmItems = new List<Config>();
            SandboxItems = new List<Config>();
        }

        public List<Config> GetConfigItems(bool sandboxed)
        {
            return sandboxed ? SandboxItems : FarmItems;
        }

        public Config GetConfig(bool sandboxed, string name)
        {
            var items = GetConfigItems(sandboxed);
            return items.FirstOrDefault(item => item.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
        }

        public Config GetActiveConfig(bool sandboxed)
        {
            return sandboxed ? ActiveSandboxConfig : ActiveFarmConfig;
        }

        public void SetActiveConfig(bool sandboxed, string name)
        {
            if (name == null) throw new ArgumentNullException("name");
            var config = GetConfig(sandboxed, name);
            if(config == null)
                throw new ApplicationException();

            if(sandboxed)
            {
                ActiveSandboxConfig = config;
                ActiveSandbox = name;
            }
            else
            {
                ActiveFarmConfig = config;
                ActiveFarm = name;
            }
        }

        public List<string> GetConfigNames(bool sandboxed)
        {
            var items = GetConfigItems(sandboxed);
            return items.Select(e => e.Name).ToList();
        }

        public void AddConfig(bool sandboxed, Config config)
        {
            if (config == null) throw new ArgumentNullException("config");
            var name = config.Name;
            
            Config conf = GetConfig(sandboxed, name);
            if (conf == null)
            {
                var items = GetConfigItems(sandboxed);
                items.Add(config);
                SetActiveConfig(sandboxed, name);
            }
        }

        public bool DeleteConfig(bool sandboxed, string name)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
            var items = GetConfigItems(sandboxed);
            Config conf = GetConfig(sandboxed, name);
            bool result = items.Remove(conf);
            if (result)
            {
                UpdateActiveConfig(sandboxed, name, items);
            }
            return result;
        }

        public void Save(string path)
        {
            var fullFileName = Path.Combine(path, ConfigFileName);

            using (var fs = new FileStream(fullFileName, FileMode.Create))
            {
                var xs = new XmlSerializer(typeof(ConfigContainer));
                xs.Serialize(fs, this);
            }
        }

        public static ConfigContainer Create(string path)
        {
            ConfigContainer cntr;
            try
            {
                cntr = Load(path);
                if (!string.IsNullOrEmpty(cntr.ActiveSandbox))
                {
                    cntr.SetActiveConfig(true, cntr.ActiveSandbox);
                }
                if (!string.IsNullOrEmpty(cntr.ActiveFarm))
                {
                    cntr.SetActiveConfig(false, cntr.ActiveFarm);
                }
            }
            catch
            {
                cntr = new ConfigContainer();
            }

            return cntr;
        }

        public static bool Exists(string path)
        {
            var fullFileName = Path.Combine(path, ConfigFileName);
            return File.Exists(fullFileName);
        }

        private void UpdateActiveConfig(bool sandboxed, string name, IEnumerable<Config> items)
        {
            var config = GetActiveConfig(sandboxed);
            if (config == null) return;
            if (config.Name != name) return;

            Config any = items.FirstOrDefault();
            if (any != null)
            {
                SetActiveConfig(sandboxed, any.Name);
            }
            else
            {
                if (sandboxed)
                {
                    ActiveSandboxConfig = null;
                    ActiveSandbox = "";
                }
                else
                {
                    ActiveFarmConfig = null;
                    ActiveFarm = "";
                }
            }
        }

        private static ConfigContainer Load(string path)
        {
            var fullFileName = Path.Combine(path, ConfigFileName);

            using (var fs = new FileStream(fullFileName, FileMode.OpenOrCreate))
            {
                var xs = new XmlSerializer(typeof(ConfigContainer));
                return (ConfigContainer)xs.Deserialize(fs);
            }
        }
    }
}
